#include "SGTree.h"
#include "Database.h"

//node class
#include "SGNode.h"
#include "SGNodeTranslate.h"
#include "SGNodeSeparator.h"
#include "SGNodeScale.h"
#include "SGNodeRotate.h"
#include "SGNodePrimitive.h"
#include "SGNodeMaterial.h"
#include "SGNodeLookAt.h"
#include "SGNodeDirectionalLight.h"
#include "SGNodePointLight.h"

//set the static instance variable
SGTree* SGTree::_instance = 0;

SGTree& SGTree::getInstance()
{
	if(_instance == 0)
		_instance = new SGTree();

	return *_instance;
}

void SGTree::close()
{
	if(_instance != 0)
	{
		delete _instance;
		_instance = 0;
	}
}

SGTree::SGTree(void)
:_root(0)
{
	_value.identity();
}

SGTree::~SGTree(void)
{
	//delete the tree
	/*if(_root != 0)
	{
		delete _root;
		_root = 0;
	}*/

	for(list<SGNode*>::iterator i = _nodesList.begin(); i != _nodesList.end(); i++)
	{
		if( *i != 0)
		{
			delete *i;
			*i = 0;
		}
	}

	_nodesList.clear();
}

void SGTree::setValue(const CMatrix& value)
{
	_value = value;
}

CMatrix& SGTree::getValue()
{
	return _value;
}

//get from pile
void SGTree::pop()
{
	if (_stack.empty())
	{
		_value.identity();
		return;
	}

	_value = _stack.top();
	_stack.pop();
}

//put on pile
void SGTree::push()
{
	_stack.push(_value);
}

void SGTree::dirty()
{
	//dirty the root
	_root->dirty();

	//clean the stack matrix
	while(!_stack.empty())
		_stack.pop();

	//clean the current matrix
	_value.identity();
}

void SGTree::traversal()
{
	//dirty all the controllers
	//CTRLDATA.onChange();

	//traverse the tree and update everything
	_root->goThrough();
}

void SGTree::setRoot(SGNode* root)
{
	_root = root;
}

//create a translate node and return a pointer to it
SGNodeTranslate* SGTree::createNodeTranslate()
{
	SGNodeTranslate* newNode = new SGNodeTranslate();
	_nodesList.push_back(newNode);
	return newNode;
}

//create a separator node and return its pointer
SGNodeSeparator* SGTree::createNodeSeparator()
{
	SGNodeSeparator* newNode = new SGNodeSeparator();
	_nodesList.push_back(newNode);
	return newNode;
}

//create a scale node and return its pointer
SGNodeScale* SGTree::createNodeScale()
{
	SGNodeScale* newNode = new SGNodeScale();
	_nodesList.push_back(newNode);
	return newNode;
}

//create a rotate node and return its pointer
SGNodeRotate* SGTree::createNodeRotate()
{
	SGNodeRotate* newNode = new SGNodeRotate();
	_nodesList.push_back(newNode);
	return newNode;
}

//create a primitive node and return its pointer
SGNodePrimitive* SGTree::createNodePrimitive(IPrimitive* p)
{
	SGNodePrimitive* newNode = new SGNodePrimitive(p);
	_nodesList.push_back(newNode);
	return newNode;
}

//create a meterial node and return its pointer
SGNodeMaterial* SGTree::createNodeMaterial(CMaterial* m)
{
	SGNodeMaterial* newNode = new SGNodeMaterial(m);
	_nodesList.push_back(newNode);
	return newNode;
}

//create a lookat node and return its pointer
SGNodeLookAt* SGTree::createNodeLookAt()
{
	SGNodeLookAt* newNode = new SGNodeLookAt();
	_nodesList.push_back(newNode);
	return newNode;
}

//create a directional light node and return its pointer
SGNodeDirectionalLight* SGTree::createNodeDirectionalLight(CDirectionalLight* l)
{
	SGNodeDirectionalLight* newNode = new SGNodeDirectionalLight(l);
	_nodesList.push_back(newNode);
	return newNode;
}

//create a point light node and return its pointer
SGNodePointLight* SGTree::createNodePointLight(CPointLight* l)
{
	SGNodePointLight* newNode = new SGNodePointLight(l);
	_nodesList.push_back(newNode);
	return newNode;
}